import os
import snownlp
import pandas as pd
from pyecharts.charts import Bar, Line, Pie, WordCloud
from pyecharts import options as opts
from pyecharts.globals import ThemeType
from spider.models import Product, Category
import jieba.analyse


def return_products_top10(category_name):
    # 按播放量和点赞数排序取前十
    play_cnt_products = Product.objects.filter(category__category_name=category_name).order_by('-play_cnt_list',
                                                                                               '-like_cnt_list')[:10]

    favorite_cnt_products = Product.objects.filter(category__category_name=category_name).order_by('-favorite_cnt_list',
                                                                                                   '-coin_cnt_list')[
                            :10]

    share_cnt_products = Product.objects.filter(category__category_name=category_name).order_by('-reply_cnt_list',
                                                                                                '-share_cnt_list')[:10]

    danmu_cnt_products = Product.objects.filter(category__category_name=category_name).order_by('-danmu_cnt_list')[:10]
    play_cnt_x_data = [product.title for product in play_cnt_products]
    play_cnt = [product.play_cnt_list for product in play_cnt_products]
    like_cnt = [product.like_cnt_list for product in play_cnt_products]

    favorite_cnt_x_data = [product.title for product in favorite_cnt_products]
    favorite_cnt = [product.favorite_cnt_list for product in favorite_cnt_products]
    coin_cnt = [product.coin_cnt_list for product in favorite_cnt_products]

    share_cnt_x_data = [product.title for product in share_cnt_products]
    reply_cnt = [product.reply_cnt_list for product in share_cnt_products]
    share_cnt = [product.share_cnt_list for product in share_cnt_products]

    danmu_cnt_x_data = [product.title for product in danmu_cnt_products]
    danmu_cnt = [product.danmu_cnt_list for product in danmu_cnt_products]
    return play_cnt_x_data, favorite_cnt_x_data, share_cnt_x_data, danmu_cnt_x_data, play_cnt, like_cnt, favorite_cnt, coin_cnt, reply_cnt, share_cnt, danmu_cnt


# 生成 all_chart 页面所需图表
def get_all_chart(category_name):
    # 获取数据，并按播放量和点赞数排序取前十
    play_cnt_x_data, favorite_cnt_x_data, share_cnt_x_data, danmu_cnt_x_data, play_cnt, like_cnt, favorite_cnt, coin_cnt, reply_cnt, share_cnt, danmu_cnt = return_products_top10(
        category_name)
    # 柱状图 - 播放和点赞前十
    bar1 = (
        Bar(init_opts=opts.InitOpts(width='100%', height='400px', theme=ThemeType.LIGHT))
        .add_xaxis(play_cnt_x_data)
        .add_yaxis("播放量", play_cnt)
        .add_yaxis("点赞数", like_cnt)
        .set_global_opts(
            title_opts=opts.TitleOpts(title="播放和点赞前十柱状图"),
            xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45))
        )
    )
    # 折线图 - 收藏和投币前十
    line1 = (
        Line(init_opts=opts.InitOpts(width='100%', height='400px', theme=ThemeType.LIGHT))
        .add_xaxis(favorite_cnt_x_data)
        .add_yaxis("收藏数", favorite_cnt)
        .add_yaxis("投币数", coin_cnt)
        .set_global_opts(
            title_opts=opts.TitleOpts(title="收藏和投币前十折线图"),
            xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45))
        )
    )
    # 折线图 - 评论数和分享数前十
    line2 = (
        Line(init_opts=opts.InitOpts(width='100%', height='400px', theme=ThemeType.LIGHT))
        .add_xaxis(share_cnt_x_data)
        .add_yaxis("评论数", reply_cnt)
        .add_yaxis("分享数", share_cnt)
        .set_global_opts(
            title_opts=opts.TitleOpts(title="评论数和分享数前十折线图"),
            xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45))
        )
    )
    # 柱状图 - 弹幕数前十
    bar2 = (
        Bar(init_opts=opts.InitOpts(width='100%', height='400px', theme=ThemeType.LIGHT))
        .add_xaxis(danmu_cnt_x_data)
        .add_yaxis("弹幕数", danmu_cnt)
        .set_global_opts(
            title_opts=opts.TitleOpts(title="弹幕数前十柱状图"),
            xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45))
        )
    )
    return bar1, line1, line2, bar2


# 生成 index.html 第一个 card-body 所需的各分类分区 TOP-1 播放量折线图
def get_category_top1_play():
    category_name = {
        'all': '全分区',
        'animation': '动画',
        'music': '音乐',
        'dance': '舞蹈',
        'game': '游戏',
        'knowledge': '知识',
        'technology': '科技',
        'motion': '运动',
        'car': '汽车',
        'live': '生活',
        'food': '美食',
        'animal': '动物',
        'ghost_animal': '鬼畜',
        'vogue': '时尚',
        'amusement': '娱乐',
        'film': '影视',
        'original': '原创',
        'newcomer': '新人',
    }
    categories = Category.objects.all()
    x_data = []
    y_data = []
    for category in categories:
        top_product = Product.objects.filter(category=category).order_by('-play_cnt_list').first()
        if top_product:
            # 将英文分类名称转换为中文
            chinese_name = category_name.get(category.category_name.lower(), category.category_name)
            x_data.append(chinese_name)
            y_data.append(top_product.play_cnt_list)
    line = (
        Line(init_opts=opts.InitOpts(width='100%', height='400px', theme=ThemeType.LIGHT))
        .add_xaxis(x_data)  # 使用动态生成的 x_data 列表
        .add_yaxis("播放量", y_data)
        .set_global_opts(
            # title_opts=opts.TitleOpts(title="各分类分区 TOP-1 播放量折线图"),
            xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45)),
            toolbox_opts=opts.ToolboxOpts(is_show=True, feature={
                "dataZoom": {
                    "yAxisIndex": "none"
                },
                "restore": {}
                # "saveAsImage": {}
            })
        )
    )
    return line


# 生成 index.html 第二个 card-body 所需的按照播放、点赞、投币降序排列前 top-18 各分区饼状图占比
def get_top18_category_pie():
    all_products = Product.objects.exclude(category__category_name='all')
    category_count = {}
    for product in all_products:
        category = product.category.category_name
        category_count[category] = category_count.get(category, 0) + 1
    sorted_categories = sorted(category_count.items(), key=lambda item: item[1], reverse=True)[:18]
    x_data = ['动画', '音乐', '舞蹈', '游戏', '知识', '科技', '运动', '汽车', '生活', '美食', '动物', '鬼畜',
              '时尚', '娱乐', '影视', '原创', '新人']
    y_data = [item[1] for item in sorted_categories]
    pie = (
        Pie(init_opts=opts.InitOpts(width='100%', height='400px', theme=ThemeType.LIGHT))
        .add(
            "",
            [list(z) for z in zip(x_data, y_data)],
            radius=["30%", "75%"],
        )
        .set_global_opts(
            # title_opts=opts.TitleOpts(title="按播放、点赞、投币降序排列前 top-18 各分区饼状图占比"),
            legend_opts=opts.LegendOpts(orient="vertical", pos_top="15%", pos_left="2%"),
        )
        .set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {c}"))
    )
    return pie


def wordcloud_view(bv):
    # 读取数据，这里假设数据存储在 CSV 文件中
    df = pd.read_csv(f'./upload/comment/{bv}_弹幕.csv')
    v_cmt_list = df['弹幕内容'].values.tolist()
    v_cmt_list = [str(i) for i in v_cmt_list]
    v_cmt_str = ' '.join(v_cmt_list)
    keywords = jieba.analyse.extract_tags(v_cmt_str, withWeight=True, topK=100)

    # 创建词云图
    wordcloud = (
        WordCloud(init_opts=opts.InitOpts(width='100%', height='400px', theme=ThemeType.LIGHT))
        .add("", keywords, word_size_range=[20, 100])
        .set_global_opts(title_opts=opts.TitleOpts(title="弹幕词云图"))
    )
    return wordcloud


def sentiment_pie_view(bv):
    # 读取数据
    # print(os.getcwd())
    df = pd.read_csv(f'./upload/comment/{bv}_弹幕.csv')

    v_cmt_list = df['弹幕内容'].values.tolist()
    v_cmt_list = [str(i) for i in v_cmt_list]

    # 情感分析
    pos_count = 0
    neg_count = 0
    for comment in v_cmt_list:
        sentiments_score = snownlp.SnowNLP(comment).sentiments
        if sentiments_score < 0.3:
            neg_count += 1
        else:
            pos_count += 1

    # 创建饼图
    pie = (
        Pie(init_opts=opts.InitOpts(width='100%', height='400px', theme=ThemeType.LIGHT))
        .add(
            "",
            [("积极", pos_count), ("消极", neg_count)],
            radius=["30%", "75%"],
        )
        .set_global_opts(title_opts=opts.TitleOpts(title="弹幕情感分析图"))
        .set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {d}%"))
    )
    return pie


def compare_with_top5(bvid):
    product = Product.objects.get(BVID=bvid)
    category = product.category
    # 获取该分类下点赞、投币、收藏数前五的产品
    top5_like = Product.objects.filter(category=category).order_by('-like_cnt_list')[:5]
    top5_coin = Product.objects.filter(category=category).order_by('-coin_cnt_list')[:5]
    top5_favorite = Product.objects.filter(category=category).order_by('-favorite_cnt_list')[:5]

    # 提取数据
    top5_like_cnt = [p.like_cnt_list for p in top5_like]
    top5_coin_cnt = [p.coin_cnt_list for p in top5_coin]
    top5_favorite_cnt = [p.favorite_cnt_list for p in top5_favorite]

    x_data = ["你的视频"] + [f"Top{i + 1}" for i in range(5)]

    # 以本视频的点赞、投币、收藏数为基数 100% 进行换算
    like_base = product.like_cnt_list if product.like_cnt_list > 0 else 1
    coin_base = product.coin_cnt_list if product.coin_cnt_list > 0 else 1
    favorite_base = product.favorite_cnt_list if product.favorite_cnt_list > 0 else 1

    like_cnt = [100] + [int((like / like_base) * 100) for like in top5_like_cnt]
    coin_cnt = [100] + [int((coin / coin_base) * 100) for coin in top5_coin_cnt]
    favorite_cnt = [100] + [int((favorite / favorite_base) * 100) for favorite in top5_favorite_cnt]

    # 绘制柱状图
    bar = (
        Bar(init_opts=opts.InitOpts(width='100%', height='600px', theme=ThemeType.LIGHT))
        .add_xaxis(x_data)
        .add_yaxis("点赞数（%）", like_cnt)
        .add_yaxis("投币数（%）", coin_cnt)
        .add_yaxis("收藏数（%）", favorite_cnt)
        .set_global_opts(
            title_opts=opts.TitleOpts(title="点赞、投币、收藏与分类前5对比柱状图（以本视频为 100%）"),
            xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45)),
            legend_opts=opts.LegendOpts(pos_top="5%")
        )
    )
    return bar


def analysis_chart(bvid):
    product = Product.objects.get(BVID=bvid)
    # 获取该产品的作者
    author = product.author_list.first()
    if author:
        # 使用自定义的 related_name 访问关联的 Product 对象
        # 获取该作者的其他产品，按播放量降序排序，取前 5 个
        author_products = author.author_list.exclude(BVID=bvid).order_by('-play_cnt_list')[:5]
        # 将当前产品添加到列表中
        all_products = list(author_products) + [product]
        # 按播放量排序
        all_products.sort(key=lambda p: p.play_cnt_list, reverse=True)

        x_data = [p.title for p in all_products]
        play_cnt = [p.play_cnt_list for p in all_products]
        like_cnt = [p.like_cnt_list for p in all_products]

        # 绘制折线图
        line = (
            Line(init_opts=opts.InitOpts(width='100%', height='400px', theme=ThemeType.LIGHT))
            .add_xaxis(x_data)
            .add_yaxis("播放量", play_cnt)
            .add_yaxis("点赞数", like_cnt)
            .set_global_opts(
                title_opts=opts.TitleOpts(title="同作者其他视频及当前视频播放量和点赞数折线图"),
                xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45)),
                legend_opts=opts.LegendOpts(pos_top="5%")
            )
        )
        return line
    return None


def wordcloud2_view(bv):
    # 读取数据数据存储在 CSV 文件中
    df = pd.read_csv(f'./upload/comment/{bv}_评论.csv', encoding='utf-8')
    v_cmt_list = df['评论内容'].values.tolist()
    v_cmt_list = [str(i) for i in v_cmt_list]
    v_cmt_str = ' '.join(v_cmt_list)
    keywords = jieba.analyse.extract_tags(v_cmt_str, withWeight=True, topK=100)

    # 创建词云图
    wordcloud = (
        WordCloud(init_opts=opts.InitOpts(width='100%', height='400px', theme=ThemeType.LIGHT))
        .add("", keywords, word_size_range=[20, 100])
        .set_global_opts(title_opts=opts.TitleOpts(title="评论词云图"))
    )
    return wordcloud


def sentiment2_pie_view(bv):
    # 读取数据
    # print(os.getcwd())
    df = pd.read_csv(f'./upload/comment/{bv}_评论.csv', encoding='utf-8')

    v_cmt_list = df['评论内容'].values.tolist()
    v_cmt_list = [str(i) for i in v_cmt_list]

    # 情感分析
    pos_count = 0
    neg_count = 0
    for comment in v_cmt_list:
        sentiments_score = snownlp.SnowNLP(comment).sentiments
        if sentiments_score < 0.3:
            neg_count += 1
        else:
            pos_count += 1

    # 创建饼图
    pie = (
        Pie(init_opts=opts.InitOpts(width='100%', height='400px', theme=ThemeType.LIGHT))
        .add(
            "",
            [("积极", pos_count), ("消极", neg_count)],
            radius=["30%", "75%"],
        )
        .set_global_opts(title_opts=opts.TitleOpts(title="评论情感分析图"))
        .set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {d}%"))
    )
    return pie


def audience_activity_combine(bv):
    # 读取弹幕数据
    danmu_df = pd.read_csv(f'./upload/comment/{bv}_弹幕.csv')
    # 将弹幕时间列转换为 datetime 类型
    danmu_df['弹幕时间'] = pd.to_datetime(danmu_df['弹幕时间'])
    # 按弹幕时间分组统计数量
    danmu_count = danmu_df.groupby(danmu_df['弹幕时间'].dt.hour)['弹幕内容'].count()

    # 读取评论数据
    comment_df = pd.read_csv(f'./upload/comment/{bv}_评论.csv', encoding='utf-8')
    # 将评论时间列转换为 datetime 类型
    comment_df['评论时间'] = pd.to_datetime(comment_df['评论时间'])
    # 按评论时间分组统计数量
    comment_count = comment_df.groupby(comment_df['评论时间'].dt.hour)['评论内容'].count()

    # 确保时间范围一致
    all_hours = list(range(24))
    danmu_count = danmu_count.reindex(all_hours, fill_value=0)
    comment_count = comment_count.reindex(all_hours, fill_value=0)

    x_data = all_hours
    danmu_y_data = danmu_count.values.tolist()
    comment_y_data = comment_count.values.tolist()

    # 绘制折线图
    line = (
        Line(init_opts=opts.InitOpts(width='100%', height='600px', theme=ThemeType.LIGHT))
        .add_xaxis(x_data)
        .add_yaxis("弹幕数量", danmu_y_data)
        .add_yaxis("评论数量", comment_y_data)
        .set_global_opts(
            title_opts=opts.TitleOpts(title="按时间统计的弹幕和评论数量，反映观众活跃率"),
            xaxis_opts=opts.AxisOpts(name="小时"),
            yaxis_opts=opts.AxisOpts(name="数量"),
            legend_opts=opts.LegendOpts(pos_top="5%"),
            # 添加工具箱，包含缩放功能
            toolbox_opts=opts.ToolboxOpts(is_show=True, feature={
                "dataZoom": {
                    "yAxisIndex": "none"
                },
                "restore": {}
                # "saveAsImage": {}
            })
        )
    )
    return line
